package com.google.jessewilson.codesearch.api;

import com.google.jessewilson.codesearch.api.spi.SearchProviderBackend;
import com.google.jessewilson.codesearch.io.Path;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A file result from a search provider.
 *
 * @author jessewilson
 */
public final class CodeFile {

  private String id;
  private Date updated;
  private ContentRoot contentRoot;
  private Path path;
  private boolean availableLocally;

  private final Map<Class<? extends CodeFileExtra>,CodeFileExtra> codeFileExtrasByType = new ConcurrentHashMap<Class<? extends CodeFileExtra>,CodeFileExtra>();

  /** the search provider that created this code file */
  private SearchProviderBackend searchProviderBackend;

  /**
   * A unique identifier for this file, such as a URI.
   */
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }

  public Date getUpdated() {
    return updated;
  }
  public void setUpdated(Date updated) {
    this.updated = updated;
  }

  /**
   * Contains a name attribute and a uri attribute that together specify the
   * location of the package: either a version-control server or a compressed
   * contentRoot.
   */
  public ContentRoot getContentRoot() {
    return contentRoot;
  }
  public void setContentRoot(ContentRoot contentRoot) {
    this.contentRoot = contentRoot;
  }

  /**
   * Contains a name attribute specifying the name of the file within the
   * version-control server or compressed contentRoot.
   */
  public Path getPath() {
    return path;
  }
  public void setPath(Path path) {
    this.path = path;
  }

  /**
   * The search provider that this path is from.
   */
  public SearchProviderBackend getSearchProvider() {
    return searchProviderBackend;
  }
  public void setSearchProvider(SearchProviderBackend searchProviderBackend) {
    this.searchProviderBackend = searchProviderBackend;
  }

  /**
   * Whether a file with the same name is available without download.
   * This is useful when codesearch is used to search files in the local
   * project.
   */
  public boolean isAvailableLocally() {
    return availableLocally;
  }
  public void setAvailableLocally(boolean availableLocally) {
    this.availableLocally = availableLocally;
  }

  public <T extends CodeFileExtra> T getCodeFileExtra(Class<T> codeFileExtraClass) {
    return (T)codeFileExtrasByType.get(codeFileExtraClass);
  }
  public <T extends CodeFileExtra> void setCodeFileExtra(Class<T> codeFileExtraClass, T codeFileExtra) {
    codeFileExtrasByType.put(codeFileExtraClass, codeFileExtra);
  }

  @Override
  public String toString() {
    return getPath().toString();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    CodeFile codeFile = (CodeFile) o;
    if (!id.equals(codeFile.id)) {
      return false;
    }
    return true;
  }

  @Override
  public int hashCode() {
    return id.hashCode();
  }
}
